Imports System.Web.HttpContext

Public Class QuestionnaireNode
    Public ID As Integer
    Public StudyID As String
    Public InstrumentID As String
    Public VisitNumber As Byte
    Public Description As String
    Public Instruction As String
    Public CreatedDate As Date
    Public CreatedBy As String
    Public LastUpdated As Date
    Public LastUpdatedBy As String
    Public EdtingPermission As String
    Public TakingPermission As String

    Private _instrument As InstrumentNode
    Private _answerTable As Hashtable
    Private _prevNodeTable As Hashtable
    Private _enabledQuestionsTable As Hashtable
    Private _lock As New Object

    Public Const _answerTableSession As String = "_Taker_AnswerTable"
    Public Const _previousNodeTableSession As String = "_Taker_PrevTable"
    Public Const _lastActiveNodeSession As String = "_Taker_LastActiveNode"
    Private Const _enabledQuestionsSession As String = "_Taker_EnabledQuestions"

    Public ReadOnly Property Instrument() As InstrumentNode
        Get
            If _instrument Is Nothing Then
                _instrument = QuestionnaireTakerODS.Provider.BuildInstrumentNode(InstrumentID)
            End If
            Return _instrument
        End Get
    End Property

    Public Sub New(ByVal id As Integer)
        Me.ID = id
    End Sub


#Region "Public Subs and Functons"

    Public Property CurrentNode() As IQuestionNode
        Get
            Return Me.Instrument.CurrentNode
        End Get
        Set(ByVal value As IQuestionNode)
            Me.Instrument.CurrentNode = value
        End Set
    End Property

    Public ReadOnly Property FirstQuestionNode() As IQuestionNode
        Get
            Return Me.Instrument.FirstQuestionNode
        End Get
    End Property

    Private ReadOnly Property AnswerTable() As Hashtable
        Get
            Me._answerTable = CType(Current.Session(_answerTableSession), Hashtable)
            If (Me._answerTable Is Nothing) Then
                SyncLock _lock
                    Me._answerTable = New Hashtable
                    Current.Session(_answerTableSession) = Me._answerTable
                End SyncLock
            End If
            Return Me._answerTable
        End Get
    End Property

    Private ReadOnly Property PreviousNodeTable() As Hashtable
        Get
            Me._prevNodeTable = CType(Current.Session(_previousNodeTableSession), Hashtable)
            If (Me._prevNodeTable Is Nothing) Then
                SyncLock _lock
                    Me._prevNodeTable = New Hashtable
                    Current.Session(_previousNodeTableSession) = Me._prevNodeTable
                End SyncLock
            End If
            Return Me._prevNodeTable
        End Get
    End Property

    Private ReadOnly Property EnabledQuestionsTable() As Hashtable
        Get
            Me._enabledQuestionsTable = CType(Current.Session(_enabledQuestionsSession), Hashtable)
            If (Me._enabledQuestionsTable Is Nothing) Then
                SyncLock _lock
                    Me._enabledQuestionsTable = New Hashtable
                    Current.Session(_enabledQuestionsSession) = Me._enabledQuestionsTable
                End SyncLock
            End If
            Return Me._enabledQuestionsTable
        End Get
    End Property

    Public Sub GetAnswerFromDB()
        ' Get Answer from Database
        SyncLock _lock
            Me._answerTable = QuestionnaireTakerODS.Provider.GetAnswerFromDB( _
                Me.ID, Me.InstrumentID, Current.User.Identity.Name)
            Current.Session(_answerTableSession) = Me._answerTable
            Current.Session(_enabledQuestionsSession) = Nothing
            Current.Session(_previousNodeTableSession) = Nothing
            Me.EnabledQuestionsTable(Me.CurrentNode.UID) = True

            Dim _next As IQuestionNode = GetNextQuestionNode(Me.CurrentNode)
            Do While Not (_next Is Nothing)
                Dim _curNum As String = Me.CurrentNode.QuestionNumber
                If _next.ParentNode Is Nothing Then
                    ' It is a QuestionNode
                    Dim num As Integer = _curNum.Split(".")(0)
                    _next.QuestionNumber = num + 1
                    Me.EnabledQuestionsTable(_next.UID) = True
                Else
                    ' It is a LogicNode
                    If _curNum.Contains(".") Then
                        Dim nums As String() = _curNum.Split(".")
                        Dim num As Integer = nums(1)
                        _next.QuestionNumber = nums(0) & "." & num + 1
                    Else
                        _next.QuestionNumber = _curNum & ".1"
                    End If
                End If
                Me.PreviousNodeTable.Item(_next.UID) = Me.CurrentNode.UID
                Me.CurrentNode = _next
                _next = GetNextQuestionNode(Me.CurrentNode)
            Loop
            Current.Session(_lastActiveNodeSession) = Me.CurrentNode
        End SyncLock
    End Sub

    Public Function FindAnswer(ByVal uid As Guid) As String
        If Me.AnswerTable.Contains(uid) Then
            Return Me.AnswerTable(uid).ToString
        End If
        'Throw New Exception("Cannot find the answer for " & uid.ToString)
        Return String.Empty
    End Function

    Public Function GetQuestion(ByVal questionId As Integer) As Question
        Return QuestionnaireTakerODS.Provider.GetQuestion(questionId)
    End Function

    Public Function GetChoices(ByVal questionId As Integer) As DataTable
        Return QuestionnaireTakerODS.Provider.GetChoices(questionId)
    End Function

    Public Function IsEnabledQuestion(ByVal uid As Guid) As Boolean
        ' This function is used for the Question Navigator Bar
        If Me.EnabledQuestionsTable.Contains(uid) Then
            Return Me.EnabledQuestionsTable(uid)
        End If
        Return False
    End Function

#End Region


#Region "Questionnaire Logistic"

    'private function TestOperand(answer as String,

    Private Function TestLogic( _
        ByVal logic As String, _
        ByVal config As String, _
        ByVal answer As String) As Boolean
        If logic.Substring(0, 1) <> config.Substring(0, 1) Then
            Return False
        End If
        Dim logs As String() = logic.Split("|")
        '0: Type, 1: Operand, ...
        If logs(3) = "-1" Then
            ' No condition
            Return True
        End If
        'Dim ans As String() = answer.Split("|")
        ''0: Answer, 1: Another anser (date, time)
        Select Case logs(0)
            Case "1"    ' Date
                Select Case logs(3)
                    Case "0"    'Specific date
                        Dim date1 As Date = CDate(answer).ToShortDateString
                        Dim date2 As Date = CDate(logs(2)).ToShortDateString
                        Select Case logs(1) 'Operand
                            Case "0"    '=
                                Return date1 = date2
                            Case "1"    '<>
                                Return date1 <> date2
                            Case "2"    '>
                                Return date1 > date2
                            Case "3"    '>=
                                Return date1 >= date2
                            Case "4"    '<
                                Return date1 < date2
                            Case "5"    '<=
                                Return date1 <= date2
                            Case Else
                                Return False
                        End Select
                    Case "1"    'Cover the specific date
                        Dim ans As String() = answer.Split("|")
                        Dim date1 As Date = CDate(ans(0)).ToShortDateString
                        Dim date2 As Date = CDate(ans(1)).ToShortDateString
                        Dim date3 As Date = CDate(logs(2)).ToShortDateString
                        Return date1 <= date3 AndAlso date3 <= date2
                    Case "2"    'Not cover the specific date
                        Dim ans As String() = answer.Split("|")
                        Dim date1 As Date = CDate(ans(0)).ToShortDateString
                        Dim date2 As Date = CDate(ans(1)).ToShortDateString
                        Dim date3 As Date = CDate(logs(2)).ToShortDateString
                        Return date3 < date1 OrElse date2 < date3
                    Case "3"    'Number of days in range
                        Dim ans As String() = answer.Split("|")
                        Dim date1 As Date = CDate(ans(0)).ToShortDateString
                        Dim date2 As Date = CDate(ans(1)).ToShortDateString
                        Dim daysIn As Integer = date2.Subtract(date1).Days
                        Dim days As Integer = CInt(logs(2))
                        Select Case logs(1) 'Operand
                            Case "0"    '=
                                Return daysIn = days
                            Case "1"    '<>
                                Return daysIn <> days
                            Case "2"    '>
                                Return daysIn > days
                            Case "3"    '>=
                                Return daysIn >= days
                            Case "4"    '<
                                Return daysIn < days
                            Case "5"    '<=
                                Return daysIn <= days
                            Case Else
                                Return False
                        End Select
                    Case "4"    'Lower Date
                        Dim ans As String() = answer.Split("|")
                        Dim date1 As Date = CDate(ans(0)).ToShortDateString
                        Dim date3 As Date = CDate(logs(2)).ToShortDateString
                        Select Case logs(1) 'Operand
                            Case "0"    '=
                                Return date1 = date3
                            Case "1"    '<>
                                Return date1 <> date3
                            Case "2"    '>
                                Return date1 > date3
                            Case "3"    '>=
                                Return date1 >= date3
                            Case "4"    '<
                                Return date1 < date3
                            Case "5"    '<=
                                Return date1 <= date3
                            Case Else
                                Return False
                        End Select
                    Case "5"    'Upper Date
                        Dim ans As String() = answer.Split("|")
                        Dim date2 As Date = CDate(ans(1)).ToShortDateString
                        Dim date3 As Date = CDate(logs(2)).ToShortDateString
                        Select Case logs(1) 'Operand
                            Case "0"    '=
                                Return date2 = date3
                            Case "1"    '<>
                                Return date2 <> date3
                            Case "2"    '>
                                Return date2 > date3
                            Case "3"    '>=
                                Return date2 >= date3
                            Case "4"    '<
                                Return date2 < date3
                            Case "5"    '<=
                                Return date2 <= date3
                            Case Else
                                Return False
                        End Select
                    Case Else
                        Return False
                End Select



            Case "2"    ' Float
                Dim dbl1 As Double = CDbl(answer)
                Dim dbl2 As Double = CDbl(logs(2))
                Select Case logs(1) 'Operand
                    Case "0"    '=
                        Return dbl1 = dbl2
                    Case "1"    '<>
                        Return dbl1 <> dbl2
                    Case "2"    '>
                        Return dbl1 > dbl2
                    Case "3"    '>=
                        Return dbl1 >= dbl2
                    Case "4"    '<
                        Return dbl1 < dbl2
                    Case "5"    '<=
                        Return dbl1 <= dbl2
                    Case Else
                        Return False
                End Select



            Case "3"    ' Integer
                Dim int1 As Double = CInt(answer)
                Dim int2 As Double = CInt(logs(2))
                Throw New Exception(int1 & "|" & int2)
                Select Case logs(1) 'Operand
                    Case "0"    '=
                        Return int1 = int2
                    Case "1"    '<>
                        Return int1 <> int2
                    Case "2"    '>
                        Return int1 > int2
                    Case "3"    '>=
                        Return int1 >= int2
                    Case "4"    '<
                        Return int1 < int2
                    Case "5"    '<=
                        Return int1 <= int2
                    Case Else
                        Return False
                End Select



            Case "4"    ' Multiple Choices Multiple Answers
                If logs(3) = "0" Then
                    'Individual Answer
                    Dim choiceNum As Integer = logs(2)
                    Select Case logs(1) 'Operand
                        Case "0"    '=
                            For Each int1 As Integer In answer.Split(",")
                                If int1 = choiceNum Then Return True
                            Next
                            Return False
                        Case "1"    '<>
                            For Each int1 As Integer In answer.Split(",")
                                If int1 = choiceNum Then Return False
                            Next
                            Return True
                        Case Else
                            Return False
                    End Select
                Else
                    'Number of selected answers
                    Dim arr As String() = answer.Split(",")
                    Dim num1 As Integer = 0
                    For Each s As String In arr
                        num1 = +1
                    Next
                    Dim num2 As Integer = logs(2)
                    Select Case logs(1) 'Operand
                        Case "0"    '=
                            Return num1 = num2
                        Case "1"    '<>
                            Return num1 <> num2
                        Case "2"    '>
                            Return num1 > num2
                        Case "3"    '>=
                            Return num1 >= num2
                        Case "4"    '<
                            Return num1 < num2
                        Case "5"    '<=
                            Return num1 <= num2
                        Case Else
                            Return False
                    End Select
                End If



            Case "5"    ' Multiple Choices Single Answer
                Dim num1 As Integer = answer
                Dim num2 As Integer = logs(2)
                Select Case logs(1) 'Operand
                    Case "0"    '=
                        Return num1 = num2
                    Case "1"    '<>
                        Return num1 <> num2
                    Case "2"    '>
                        Return num1 > num2
                    Case "3"    '>=
                        Return num1 >= num2
                    Case "4"    '<
                        Return num1 < num2
                    Case "5"    '<=
                        Return num1 <= num2
                    Case Else
                        Return False
                End Select



            Case "6"    ' Text
                If logs(3) = "0" Then
                    'Answer contains
                    Dim words As String() = logs(2).Split("|")
                    For Each word As String In words
                        If answer.Contains(word.Trim) Then
                            Return True
                        End If
                    Next
                    Return False
                Else
                    'Length of Answer
                    Dim num1 As Integer = 0
                    If Not String.IsNullOrEmpty(answer) Then
                        num1 = answer.Length
                    End If
                    Dim num2 As Integer = logs(2)
                    Select Case logs(1) 'Operand
                        Case "0"    '=
                            Return num1 = num2
                        Case "1"    '<>
                            Return num1 <> num2
                        Case "2"    '>
                            Return num1 > num2
                        Case "3"    '>=
                            Return num1 >= num2
                        Case "4"    '<
                            Return num1 < num2
                        Case "5"    '<=
                            Return num1 <= num2
                        Case Else
                            Return False
                    End Select
                End If



            Case "7"    ' Time
                Select Case logs(3)
                    Case "0"    'Specific time
                        Dim time1 As Date = CDate(answer).ToShortTimeString
                        Dim time2 As Date = CDate(logs(2)).ToShortTimeString
                        Select Case logs(1) 'Operand
                            Case "0"    '=
                                Return time1 = time2
                            Case "1"    '<>
                                Return time1 <> time2
                            Case "2"    '>
                                Return time1 > time2
                            Case "3"    '>=
                                Return time1 >= time2
                            Case "4"    '<
                                Return time1 < time2
                            Case "5"    '<=
                                Return time1 <= time2
                            Case Else
                                Return False
                        End Select
                    Case "1"    'Cover the specific date
                        Dim ans As String() = answer.Split("|")
                        Dim time1 As Date = CDate(ans(0)).ToShortTimeString
                        Dim time2 As Date = CDate(ans(1)).ToShortTimeString
                        Dim time3 As Date = CDate(logs(2)).ToShortTimeString
                        Return time1 <= time3 AndAlso time3 <= time2
                    Case "2"    'Not cover the specific date
                        Dim ans As String() = answer.Split("|")
                        Dim time1 As Date = CDate(ans(0)).ToShortTimeString
                        Dim time2 As Date = CDate(ans(1)).ToShortTimeString
                        Dim time3 As Date = CDate(logs(2)).ToShortTimeString
                        Return time3 < time1 OrElse time2 < time3
                    Case "3"    'Number of days in range
                        Dim ans As String() = answer.Split("|")
                        Dim time1 As Date = CDate(ans(0)).ToShortTimeString
                        Dim time2 As Date = CDate(ans(1)).ToShortTimeString
                        Dim hrsIn As Integer = time2.Subtract(time1).Hours
                        Dim hrs As Integer = CInt(logs(2))
                        Select Case logs(1) 'Operand
                            Case "0"    '=
                                Return hrsIn = hrs
                            Case "1"    '<>
                                Return hrsIn <> hrs
                            Case "2"    '>
                                Return hrsIn > hrs
                            Case "3"    '>=
                                Return hrsIn >= hrs
                            Case "4"    '<
                                Return hrsIn < hrs
                            Case "5"    '<=
                                Return hrsIn <= hrs
                            Case Else
                                Return False
                        End Select
                    Case "4"    'Lower Date
                        Dim ans As String() = answer.Split("|")
                        Dim time1 As Date = CDate(ans(0)).ToShortTimeString
                        Dim time3 As Date = CDate(logs(2)).ToShortTimeString
                        Select Case logs(1) 'Operand
                            Case "0"    '=
                                Return time1 = time3
                            Case "1"    '<>
                                Return time1 <> time3
                            Case "2"    '>
                                Return time1 > time3
                            Case "3"    '>=
                                Return time1 >= time3
                            Case "4"    '<
                                Return time1 < time3
                            Case "5"    '<=
                                Return time1 <= time3
                            Case Else
                                Return False
                        End Select
                    Case "5"    'Upper Date
                        Dim ans As String() = answer.Split("|")
                        Dim time2 As Date = CDate(ans(1)).ToShortTimeString
                        Dim time3 As Date = CDate(logs(2)).ToShortTimeString
                        Select Case logs(1) 'Operand
                            Case "0"    '=
                                Return time2 = time3
                            Case "1"    '<>
                                Return time2 <> time3
                            Case "2"    '>
                                Return time2 > time3
                            Case "3"    '>=
                                Return time2 >= time3
                            Case "4"    '<
                                Return time2 < time3
                            Case "5"    '<=
                                Return time2 <= time3
                            Case Else
                                Return False
                        End Select
                    Case Else
                        Return False
                End Select
            Case Else
                Return False
        End Select
    End Function

    'Protected Function TranslateLogic(ByVal logic As String) As String
    '    If String.IsNullOrEmpty(logic) Then
    '        Return String.Empty
    '    End If
    '    Dim val As String() = logic.Split("|")
    '    Dim sbAns As New System.Text.StringBuilder
    '    Select Case val(0)
    '        Case "1"    ' Date
    '        Case "2"    ' Float
    '        Case "3"    ' Integer
    '        Case "4"    ' Individual Answer
    '        Case "5"    ' Number of selected answers
    '        Case "6"    ' Text
    '        Case "7"    ' Time
    '    End Select
    '    sbAns.Append(TranslateOperator(val(1)))
    '    sbAns.Append(val(2))
    '    sbAns.Append(".")
    '    Return sbAns.ToString
    'End Function

    'Private Function TranslateOperator(ByVal op As String) As String
    '    Select Case op
    '        Case "0"    '=
    '        Case "1"    '<>
    '        Case "2"    '>
    '        Case "3"    '>=
    '        Case "4"    '<
    '        Case "5"    '<=
    '        Case Else
    '            Return False
    '    End Select
    'End Function


    Public Function GetQuestionNode(ByVal uid As Guid) As IQuestionNode
        ' This function is used for the Question Navigator Bar
        Dim node As IQuestionNode = QuestionnaireTakerODS.Provider.FindNode(uid)
        Me.CurrentNode = node
        With Current.Request
            Current.Response.Redirect(.FilePath.Substring(.FilePath.LastIndexOf("/") + 1))
        End With
        Return node
    End Function

    Public Function GetNextQuestionNode(ByVal answer As String) As IQuestionNode
        Me.AnswerTable(Me.CurrentNode.UID) = answer
        Current.Session(_answerTableSession) = Me.AnswerTable
        Dim nums As String() = Me.CurrentNode.QuestionNumber.Split(".")
        Dim percent As String = (CInt(nums(0)) * 100 / Me.Instrument.Questions.Count) - 0.01
        Dim status As String = percent.Substring(0, percent.IndexOf(".") + 3) & " %"
        QuestionnaireTakerODS.Provider.SetAnswer(Me.ID, _
            Me.InstrumentID, Me.CurrentNode.UID, answer, status)
        Dim _next As IQuestionNode = GetNextQuestionNode(Me.CurrentNode)
        If _next Is Nothing Then
            Current.Session(_lastActiveNodeSession) = Me.CurrentNode
            QuestionnaireTakerODS.Provider.SetAnswer(Me.ID, _
                Me.InstrumentID, Me.CurrentNode.UID, answer, "Complete")
        Else
            If _next.ParentNode Is Nothing Then
                ' It is a QuestionNode
                Dim num As Integer = nums(0)
                _next.QuestionNumber = num + 1
                Me.EnabledQuestionsTable(_next.UID) = True
            Else
                ' It is a LogicNode
                If nums.Length > 1 Then
                    Dim num As Integer = nums(1)
                    _next.QuestionNumber = nums(0) & "." & num + 1
                Else
                    _next.QuestionNumber = nums(0) & ".1"
                End If
            End If
            Me.PreviousNodeTable.Item(_next.UID) = Me.CurrentNode.UID
            If String.IsNullOrEmpty(Me.FindAnswer(_next.UID)) Then
                Current.Session(_lastActiveNodeSession) = _next
            End If
            Me.CurrentNode = _next
            With Current.Request
                Current.Response.Redirect(.FilePath.Substring(.FilePath.LastIndexOf("/") + 1))
            End With
        End If
        Return _next
    End Function

    Public Function GetNextQuestionNode(ByVal node As IQuestionNode) As IQuestionNode
        Dim _next As IQuestionNode = Nothing
        Dim answer As String = Me.FindAnswer(node.UID)
        Dim config As String = Me.GetQuestion(node.QuestionID).Configuration
        If String.IsNullOrEmpty(answer) Then
            Select Case config.Substring(0, 1)
                ' return nothing when required
                Case "4"    'MCMA
                    If config.Substring(3, 1) <> "0" Then
                        Return Nothing
                    End If
                Case "5"    'MCSA
                    Return Nothing
                Case Else
                    If config.Substring(3, 1) = "0" Then
                        Return Nothing
                    End If
            End Select
        End If
        Dim childs As IQuestionNodeCollection = QuestionnaireTakerODS.Provider.GetChildNodes(node)
        If Not childs Is Nothing Then
            For Each logicNode As LogicNode In childs
                If TestLogic(logicNode.Logic, config, answer) Then
                    'Current.Session("Status") = ("<br/>1 - Logic: " & logicNode.Logic & ", Answer: " & answer)
                    Return logicNode
                End If
            Next
        End If
        'Current.Session("Status") = "<br/> using GetNextQuestionNodeRecursive, node=" & node.UID.ToString & ", questionId=" & node.QuestionID
        _next = GetNextQuestionNodeRecursive(node)
        Return _next
    End Function

    Public Function GetNextQuestionNode() As IQuestionNode
        Dim nextQuestion As IQuestionNode = Nothing
        Dim answer As String = Me.FindAnswer(Me.CurrentNode.UID)
        Dim config As String = Me.GetQuestion(Me.CurrentNode.QuestionID).Configuration
        If String.IsNullOrEmpty(answer) Then
            Select Case config.Substring(0, 1)
                Case "4"    'MCMA
                    If config.Substring(3, 1) <> "0" Then
                        Return Nothing
                    End If
                Case "5"    'MCSA
                    Return Nothing
                Case Else
                    If config.Substring(3, 1) = "0" Then
                        Return Nothing
                    End If
            End Select
        End If
        Dim childs As IQuestionNodeCollection = QuestionnaireTakerODS.Provider.GetChildNodes(Me.CurrentNode)
        If Not childs Is Nothing Then
            For Each logicNode As LogicNode In childs
                If TestLogic(logicNode.Logic, config, answer) Then
                    nextQuestion = logicNode
                    Exit For
                End If
            Next
        End If
        If nextQuestion Is Nothing Then
            nextQuestion = GetNextQuestionNodeRecursive(Me.CurrentNode)
        End If
        If Not nextQuestion Is Nothing Then
            Me.CurrentNode = nextQuestion
            With Current.Request
                Current.Response.Redirect(.FilePath.Substring(.FilePath.LastIndexOf("/") + 1))
            End With
        End If
        Return nextQuestion
    End Function

    Private Function GetNextQuestionNodeRecursive(ByVal node As IQuestionNode) As IQuestionNode
        If node.ParentNode Is Nothing Then
            Return QuestionnaireTakerODS.Provider.GetNextSibling(node)
        Else
            Dim nextSiblings As IQuestionNodeCollection = QuestionnaireTakerODS.Provider.GetNextSiblings(node)
            If Not nextSiblings Is Nothing Then
                Dim answer As String = Me.FindAnswer(node.ParentUID)
                Dim config As String = Me.GetQuestion(node.ParentNode.QuestionID).Configuration
                If String.IsNullOrEmpty(answer) Then
                    Select Case config.Substring(0, 1)
                        Case "4"    'MCMA
                            If config.Substring(3, 1) <> "0" Then
                                Return Nothing
                            End If
                        Case "5"    'MCSA
                            Return Nothing
                        Case Else
                            If config.Substring(3, 1) = "0" Then
                                Return Nothing
                            End If
                    End Select
                End If
                For Each nextSibling As LogicNode In nextSiblings
                    'Current.Session("Status") &= ("<br/>3:UID=" & nextSibling.UID.ToString & ", questionId = " & nextSibling.QuestionID)
                    If TestLogic(nextSibling.Logic, config, answer) Then
                        'Current.Session("Status") &= ("<br/>3 - Logic Match: " & nextSibling.Logic & ", Answer: " & answer)
                        Return nextSibling
                    End If
                Next
            End If
            'Current.Session("Status") &= ("<br/>3: nextSiblings is nothing")
            Return GetNextQuestionNodeRecursive(node.ParentNode)
        End If
    End Function

    Public Function GetFirstNode() As IQuestionNode
        If Me.CurrentNode Is Me.FirstQuestionNode Then
            Return Nothing
        End If
        Me.CurrentNode = Me.FirstQuestionNode
        With Current.Request
            Current.Response.Redirect(.FilePath.Substring(.FilePath.LastIndexOf("/") + 1))
        End With
        Return Me.FirstQuestionNode
    End Function

    Public Function GetPreviousQuestionNode() As IQuestionNode
        Dim prevNodeUID As Guid = Me.PreviousNodeTable.Item(Me.CurrentNode.UID)
        If prevNodeUID = Guid.Empty Then
            Return Nothing
        Else
            Dim prevNode As IQuestionNode = QuestionnaireTakerODS.Provider.FindNode(prevNodeUID)
            Me.CurrentNode = prevNode
            With Current.Request
                Current.Response.Redirect(.FilePath.Substring(.FilePath.LastIndexOf("/") + 1))
            End With
            Return prevNode
        End If
    End Function

    Private Function GetLastAnsweredLogicNodeRecursive(ByVal node As IQuestionNode) As IQuestionNode
        Dim childs As IQuestionNodeCollection = QuestionnaireTakerODS.Provider.GetChildNodes(node)
        If childs Is Nothing Then
            Return node
        End If
        Dim last As Integer = childs.Count - 1
        For i As Integer = last To 0 Step -1
            Dim logic As LogicNode = CType(childs.Item(i), LogicNode)
            Dim answer As String = Me.FindAnswer(logic.UID)
            If Not String.IsNullOrEmpty(answer) Then
                Dim config As String = Me.GetQuestion(logic.QuestionID).Configuration
                If TestLogic(logic.Logic, config, answer) Then
                    Return GetLastAnsweredLogicNodeRecursive(logic)
                End If
            End If
        Next
        Return node
    End Function

    Private Function GetLastAnsweredNode() As IQuestionNode
        Dim nextSiblings As IQuestionNodeCollection = QuestionnaireTakerODS.Provider.GetNextSiblings(Me.FirstQuestionNode)
        If nextSiblings Is Nothing Then
            Return GetLastAnsweredLogicNodeRecursive(Me.FirstQuestionNode)
        End If
        Dim last As Integer = nextSiblings.Count - 1
        For i As Integer = last To 0 Step -1
            Dim answer As String = Me.FindAnswer(nextSiblings.Item(i).UID)
            If Not String.IsNullOrEmpty(answer) Then
                Return GetLastAnsweredLogicNodeRecursive(nextSiblings.Item(i))
            End If
        Next
        Return Me.FirstQuestionNode
    End Function

    Public Sub GetLastActiveNode()
        Me.CurrentNode = Me.LastActiveNode
        With Current.Request
            Current.Response.Redirect(.FilePath.Substring(.FilePath.LastIndexOf("/") + 1))
        End With
    End Sub

    Public ReadOnly Property LastActiveNode() As IQuestionNode
        Get
            Dim _lastActiveNode As IQuestionNode
            _lastActiveNode = CType(Current.Session(_lastActiveNodeSession), IQuestionNode)
            If _lastActiveNode Is Nothing Then
                _lastActiveNode = GetLastAnsweredNode()
                Dim _next As IQuestionNode = GetNextQuestionNode(_lastActiveNode)
                If Not _next Is Nothing Then
                    _lastActiveNode = _next
                End If
            End If
            Current.Session(_lastActiveNodeSession) = _lastActiveNode
            Return _lastActiveNode
        End Get
    End Property

    Public ReadOnly Property IsGoPreviousable() As Boolean
        Get
            Return Not (Me.CurrentNode Is Me.FirstQuestionNode)
        End Get
    End Property

    Public ReadOnly Property IsGoNextable() As Boolean
        Get
            Return Not (Me.LastActiveNode Is Me.CurrentNode)
        End Get
    End Property


#End Region
End Class
